<template>
    <div id="3d-graph" class="graph-3d"></div>
</template>

<script>
import ForceGraph3D from "3d-force-graph";
import SpriteText from "three-spritetext";

export default {
    data() {
        return {
            Graph: null,
            highlightNodes: null,
            highlightLinks: null,
            hoverNode: null,
            nodes: null,
            links: []
        };
    },
    mounted() {
        this.Graph = ForceGraph3D()(document.getElementById("3d-graph"))
            .height(1000) //画布高度
            .backgroundColor("rgba(0,0,0,0)") //画布背景色
            .showNavInfo(false) //禁用页脚
            .onNodeClick(node => {
                // Aim at node from outside it
                const distance = 100;
                const distRatio =
                    1 + distance / Math.hypot(node.x, node.y, node.z);

                const newPos =
                    node.x || node.y || node.z
                        ? {
                              x: node.x * distRatio,
                              y: node.y * distRatio,
                              z: node.z * distRatio
                          }
                        : { x: 0, y: 0, z: distance }; // special case if node is in (0,0,0)
                this.Graph.cameraPosition(
                    newPos, // new position
                    node, // lookAt ({ x, y, z })
                    3000 // ms transition duration
                );
            })
            .nodeResolution(32);
        this.highlightNodes = new Set();
        this.highlightLinks = new Set();
        this.hoverNode = null;
        this.nodes = [
            {
                id: 1, //节点id
                labels: [
                    "N2" //自定义层级
                ],
                property: {
                    name: "Sparta数海数据平台" //节点文本
                },
                name: "Sparta数海数据平台", //节点文本
                group: 0
            },
            {
                id: 13,
                labels: ["N3"],
                property: {
                    name: "数据应用"
                },
                name: "数据应用",
                color: [
                    //节点颜色
                    "rgba(215,255,171,1)", //高亮时的颜色
                    "rgba(215,255,171,0.2)" //
                ],
                group: 1
            },
            {
                id: 14,
                labels: ["N4"],
                property: {
                    name: "数据管控"
                },
                name: "数据管控",
                typeNum: 0,
                group: 2,
                color: ["rgba(215,255,171,1)", "rgba(215,255,171,0.2)"]
            },
            {
                id: 15,
                labels: ["N4"],
                property: {
                    name: "数据发布"
                },
                name: "数据发布",
                typeNum: 0,
                group: 2,
                color: ["rgba(215,255,171,1)", "rgba(215,255,171,0.2)"]
            },
            {
                id: 16,
                labels: ["N4"],
                property: {
                    name: "数据资产"
                },
                name: "数据资产",
                typeNum: 0,
                group: 2,
                color: ["rgba(215,255,171,1)", "rgba(215,255,171,0.2)"]
            },
            {
                id: 17,
                labels: ["N4"],
                property: {
                    name: "数据集成"
                },
                name: "数据集成",
                typeNum: 0,
                group: 2,
                color: ["rgba(215,255,171,1)", "rgba(215,255,171,0.2)"]
            },
            {
                id: 18,
                labels: ["N4"],
                property: {
                    name: "数据处理"
                },
                name: "数据处理",
                typeNum: 0,
                group: 2,
                color: ["rgba(215,255,171,1)", "rgba(215,255,171,0.2)"]
            }
        ];
        this.links = [
            {
                id: 2, //线id
                start: 1, //连线开始节点 id
                end: 13, //连线结束节点的id
                type: "内容明细", //线上文字
                identity: null,
                property: {},
                source: 1, //连线开始节点 id
                target: 13, //连线开始节点 id
                isShow: true, //是否显示线
                group: 1,
                typeNum: 0
            },
            {
                id: 27,
                start: 1,
                end: 14,
                type: "内容明细",
                identity: null,
                property: {},
                source: 1,
                target: 14,
                isShow: true,
                group: 1,
                typeNum: 1
            },
            {
                id: 3,
                start: 1,
                end: 15,
                type: "解读",
                identity: null,
                property: {},
                source: 1,
                target: 15,
                isShow: true,
                typeNum: 0,
                group: 2
            },
            {
                id: 3,
                start: 1,
                end: 16,
                type: "解读",
                identity: null,
                property: {},
                source: 1,
                target: 16,
                isShow: true,
                typeNum: 0,
                group: 2
            },
            {
                id: 3,
                start: 1,
                end: 17,
                type: "解读",
                identity: null,
                property: {},
                source: 1,
                target: 17,
                isShow: true,
                typeNum: 0,
                group: 2
            },
            {
                id: 3,
                start: 1,
                end: 18,
                type: "解读",
                identity: null,
                property: {},
                source: 1,
                target: 18,
                isShow: true,
                typeNum: 0,
                group: 2
            }
        ];
        // this.buildNeighboursAndTestPos({
        //     nodes: this.nodes,
        //     links: this.links
        // });
        //    加入数据
        this.Graph.graphData({
            nodes: this.nodes,
            links: this.links
        });

        this.node();
        this.linkText();
        this.linkArrow();
    },
    methods: {
        // node 节点，添加周围的节点和线
        buildNeighboursAndTestPos(data) {
            return data.links.forEach(link => {
                const a = data.nodes.find(item => item.id == link.start);
                const b = data.nodes.find(item => item.id == link.end);
                !a.neighbors && (a.neighbors = []);
                !b.neighbors && (b.neighbors = []);
                a.neighbors.push(b);
                b.neighbors.push(a);
                !a.links && (a.links = []);
                !b.links && (b.links = []);
                a.links.push(link);
                b.links.push(link);
            });
        },
        // 渲染节点
        node() {
            this.Graph.nodeThreeObject(node => {
                const sprite = new SpriteText(`${node.name}`);
                sprite.color = "rgba(255, 255, 255)";
                sprite.textHeight = 1.5;
                sprite.fontSize = 120;
                sprite.fontWeight = "bold";
                sprite.position.set(0, 13, 0);
                return sprite;
            })
                .nodeThreeObjectExtend(true)
                // 节点是否隐藏
                // .nodeVisibility(node => {
                //   if (node.id == 0) return true
                //   return node.show ? true : false
                // })
                .nodeOpacity(1)
                .nodeColor(node => {
                    if (!node.color) return;
                    if (!this.highlightNodes.size) return node.color[0];
                    return this.highlightNodes.has(node)
                        ? node.color[0]
                        : node.color[1];
                })
                .nodeRelSize(8)
                // 节点文字
                .linkThreeObjectExtend(true);
        },
        // 线和线上文字
        linkText() {
            this.Graph.linkThreeObjectExtend(true)
                .linkThreeObject(link => {
                    const sprite = new SpriteText(`${link.type}`);
                    sprite.color = "rgba(255, 255, 255)";
                    sprite.textHeight = 1.5;
                    return sprite;
                })
                .linkPositionUpdate((sprite, { start, end }) => {
                    const middlePos = Object.assign(
                        ...["x", "y", "z"].map(c => ({
                            [c]: start[c] + (end[c] - start[c]) / 2 // calc middle point
                        }))
                    );
                    // Position sprite
                    Object.assign(sprite.position, middlePos);
                })
                // 曲线
                .linkCurvature(0)
                // 线颜色
                .linkColor(link => {
                    if (!this.highlightLinks.size) {
                        return this.nodes.find(item => item.id == link.end)
                            .color[0];
                    }
                    return this.highlightLinks.has(link)
                        ? this.nodes.find(item => item.id == link.end).color[0]
                        : this.nodes.find(item => item.id == link.end).color[1];
                })
                // 线宽度
                // .linkWidth(link => 0.3)
                .linkWidth(link => (this.highlightLinks.has(link) ? 1 : 0.3))
                .linkOpacity(0.7);
        },
        // 箭头
        linkArrow() {
            this.Graph.linkDirectionalArrowLength(2).linkDirectionalArrowRelPos(
                1
            );
        }
    }
};
</script>

<style lang="less"></style>
